package com.yzc.service;


import com.yzc.mapper.PredictionMapper;
import com.yzc.model.entity.prediction.PredictionDataBean;
import com.yzc.model.query.prediction.PredictionReq;
import com.yzc.util.HolidaySet;

import org.apache.commons.math3.stat.regression.OLSMultipleLinearRegression;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.List;

@Service
public class PredictionService {

    @Autowired
    private PredictionMapper predictionMapper;

    public double predictVisitorCount(PredictionReq date) {
        LocalDate baseDate = LocalDate.of(2023, 1, 1);
        List<PredictionDataBean> touristDataList = predictionMapper.loadAll();

        OLSMultipleLinearRegression regression = new OLSMultipleLinearRegression();

        // 准备自变量和因变量的数组
        int dataSize = touristDataList.size();
        double[][] independentVariables = new double[dataSize][4];  // 假设有4个自变量
        double[] dependentVariables = new double[dataSize];

        // 填充自变量和因变量数组
        int i = 0;
        for (PredictionDataBean data : touristDataList) {
            // 自变量：日期、是否周末、票价、是否假期
            independentVariables[i][0] = ChronoUnit.DAYS.between(baseDate, data.getDate());  // 从2023年1月1日开始的天数
            independentVariables[i][1] = data.isWeekend() ? 1 : 0;    // 是否周末
            independentVariables[i][2] = data.getTicketPrice();        // 票价
            independentVariables[i][3] = data.isHoliday() ? 1 : 0;     // 是否假期

            // 因变量：游客数量
            dependentVariables[i] = data.getUsersCount();
            i++;
        }

        // 进行回归分析
        regression.newSampleData(dependentVariables, independentVariables);
        double[] regressionCoefficients = regression.estimateRegressionParameters();

        boolean isWeekend = isWeekend(date.getDate());
        boolean isHoliday = HolidaySet.isHoliday(date.getDate());

        double targetDateEpoch = ChronoUnit.DAYS.between(baseDate, date.getDate());
        double targetWeekend = isWeekend ? 1 : 0;
        double targetTicketPrice = date.getTicketPrice();
        double targetHoliday = isHoliday ? 1 : 0;

        // 计算预测结果
        double predictedValue = regressionCoefficients[0]  // 截距项
                + regressionCoefficients[1] * targetDateEpoch  // 日期
                + regressionCoefficients[2] * targetWeekend   // 是否周末
                + regressionCoefficients[3] * targetTicketPrice // 票价
                + regressionCoefficients[4] * targetHoliday;   // 是否假期

        return Math.round(predictedValue);
    }

    private boolean isWeekend(LocalDate date) {
        return (date.getDayOfWeek() == DayOfWeek.SATURDAY || date.getDayOfWeek() == DayOfWeek.SUNDAY);
    }

}
